import paho.mqtt.client as mqtt_client
import time,json,logging,random
import serial
import serial.tools.list_ports
from report import Report

# 远程控制主题
topicCharge = "vehicle/home1/command/charge"
topicGo = "vehicle/home1/command/go"

topics = [(topicCharge,0),(topicGo,0)]

# TCP 连接
broker = 'broker.emqx.io'
port = 1883
client_id = f'python-mqtt-{random.randint(0, 1000)}'
username = 'admin'
password = 'public'

FIRST_RECONNECT_DELAY = 1
RECONNECT_RATE = 2
MAX_RECONNECT_COUNT = 12
MAX_RECONNECT_DELAY = 60

reportClient = None   # 全局ReportClient实例

# 配置串口参数
ser = serial.Serial(
    port='COM3',        # 串口号
    baudrate=9600,      # 波特率
    parity=serial.PARITY_NONE,  # 校验位
    stopbits=serial.STOPBITS_ONE,  # 停止位
    bytesize=serial.EIGHTBITS,  # 数据位
    timeout=1           # 读取超时设置
)

def find_serial_ports():
    ports = serial.tools.list_ports.comports()
    available_ports = []
    for port, desc, hwid in sorted(ports):
        available_ports.append(port)
        print("Found port: %s" % port)
    return available_ports

def connect_to_port(port):
    ser = serial.Serial(port, 9600, timeout=1)  # 设置波特率为9600，可以根据需要调整
    print("Connected to", port)
    return ser

##############################################
# 连接回调函数
def connect_mqtt() -> mqtt_client:
    # For paho-mqtt 2.0.0, you need to add the properties parameter.
    def on_connect(client, userdata, flags, rc, properties):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    def on_disconnect(client, userdata, rc):
        logging.info("Disconnected with result code: %s", rc)
        reconnect_count, reconnect_delay = 0, FIRST_RECONNECT_DELAY
        while reconnect_count < MAX_RECONNECT_COUNT:
            logging.info("Reconnecting in %d seconds...", reconnect_delay)
            time.sleep(reconnect_delay)

            try:
                client.reconnect()
                logging.info("Reconnected successfully!")
                return
            except Exception as err:
                logging.error("%s. Reconnect failed. Retrying...", err)

            reconnect_delay *= RECONNECT_RATE
            reconnect_delay = min(reconnect_delay, MAX_RECONNECT_DELAY)
            reconnect_count += 1
        logging.info("Reconnect failed after %s attempts. Exiting...", reconnect_count)

    # For paho-mqtt 2.0.0, you need to set callback_api_version.
    client = mqtt_client.Client(client_id=client_id, callback_api_version=mqtt_client.CallbackAPIVersion.VERSION2)

    client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.on_disconnect = on_disconnect
    client.connect(broker, port)
    return client

##############################################
# 处理接收到的JSON格式消息
def handle_message(client, msg: str):
    print(f"Handling message: {msg}")
    # 解析JSON消息
    try:
        data = json.loads(msg)
        # 处理解析后的JSON数据
        print(f"Received JSON data: {data}")
        # 提取JSON数据中的字段
        field1 = data.get("dir")
        field2 = data.get("speed")
        print(f"dir: {field1}, speed: {field2}")

        #执行Arduino运动代码
        # 发送指令到Arduino
        ser.write(f"set,{field1},{field2}\n".encode())

    except json.JSONDecodeError:
        print("Error: Invalid JSON format")
         
##############################################
# 订阅消息
def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
        if msg.topic == topicGo:
            print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
             # 处理消息
            handle_message(client, msg.payload.decode())
        elif msg.topic == topicCharge:
            print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
             # 执行自动充电的功能
            
    # 订阅多个主题
    for topic, qos in topics:
        client.subscribe(topic, qos)
    client.on_message = on_message


##############################################
# 运行MQTT客户端
def run():
    global reportClient
    global ser

    ports = find_serial_ports()
    if ports:
        chosen_port = ports[0]  # 选择第一个找到的端口，或者根据需要进行选择
        ser = connect_to_port(chosen_port)
    
    #订阅消息
    myclient = connect_mqtt()
    # 初始化ReportClient
    reportClient = Report(myclient)

    myclient.loop_start() 
    subscribe(myclient)

    try:
        while True:   # 保持循环运行, 上报电池和速度
            time.sleep(3)
            reportClient.reportBattery(30)
            reportClient.reportSpeed(119)

            # 接收串口数据
            data = ser.read(10)
            if data:
                print("接收数据:", data.decode())

    finally:
        myclient.loop_stop()
        ser.close()  # 关闭串口连接

    #myclient.loop_forever() 

if __name__ == '__main__':
    run()

